package org.xxforest.game.notsing.screen.chess;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.math.RandomUtils;
import org.xxforest.game.core.XX;
import org.xxforest.game.core.scenes.scene2d.XXLayer;
import org.xxforest.game.core.scenes.scene2d.XXNode;
import org.xxforest.game.core.scenes.scene2d.XXPointerTouch;
import org.xxforest.game.core.scenes.scene2d.events.XXEventType;
import org.xxforest.game.core.scenes.scene2d.events.listeners.XXTouchDragListener;
import org.xxforest.game.core.scenes.scene2d.events.listeners.XXTouchListener;
import org.xxforest.game.core.scenes.scene2d.events.type.XXTouchDragEvent;
import org.xxforest.game.core.scenes.scene2d.events.type.XXTouchEvent;
import org.xxforest.game.core.scenes.scene2d.graphics.XXParticle;
import org.xxforest.game.core.scenes.scene2d.selector.XXScheduleSelector;
import org.xxforest.game.core.scenes.scene2d.ui.XXImage;
import org.xxforest.game.core.scenes.scene2d.ui.XXLable;
import org.xxforest.game.core.tween.XXNodeAccessor;
import org.xxforest.game.core.tween.XXTween;
import org.xxforest.game.core.tween.XXTweenCallBack;

import aurelienribon.tweenengine.BaseTween;
import aurelienribon.tweenengine.TweenCallback;
import aurelienribon.tweenengine.equations.Linear;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class ChessLayer extends XXLayer {

	/**	分数*/
	private int mark ;
	private XXLable lable ;
	private XXLable timeLabel ;
	private int time ;
	/**	消除数量*/
	private static final float PETER_COUNT = 5 ;
	/**	棋子的宽高*/
	private static final float GIRD_WIDTH = 69 ;
	private static final float GIRD_HEIGHT = 60 ;
	
	/**	棋盘0空1白2黑*/
	private Chess [][] chesses ;
	/**	拖动事件*/
	private XXTouchDragListener dragedListener ;
	/**	松开事件*/
	private XXTouchListener touchUpListener ;
	/**	粒子效果*/
	private List<XXParticle> particles = new LinkedList<XXParticle>();
	
	public ChessLayer(float width, float height) {
		super(width, height);
	}

	public static ChessLayer create(float width, float height){
		return new ChessLayer(width, height);
	}

	@Override
	public void onCreate() {
		
		dragedListener = new XXTouchDragListener() {
			
			@Override
			public boolean handle(XXTouchDragEvent dragEvent) {
				XXNode node = dragEvent.getNode();
				if(node instanceof Chess){
					Chess chess = (Chess) node ;
					chess.touch() ;
					XXPointerTouch pointerTouch = dragEvent.getPointerTouch();
					
					XX.director.addTween(XXTween.to(chess, XXNodeAccessor.POS_XY, 0.1f)
							.ease(Linear.INOUT).target(pointerTouch.getToX() - getX(),pointerTouch.getToY() - getY()));
					
					int girdX = (int)((chess.getX() + GIRD_WIDTH / 2) / GIRD_WIDTH) ;
					int girdY = (int)((chess.getY() + GIRD_HEIGHT / 2) / GIRD_HEIGHT) ;
					
					girdX = Math.max(0, girdX);
					girdX = Math.min(chesses.length - 1, girdX);
					
					girdY = Math.max(0, girdY);
					girdY = Math.min(chesses[0].length - 1, girdY);
					
					Chess inGird = chesses[girdX][girdY];
					if(chess != inGird){
						swapPosition(chess,inGird);
						if(!inGird.isTouch()){
							XX.director.addTween(XXTween.to(inGird, XXNodeAccessor.POS_XY, 0.1f)
									.ease(Linear.INOUT).target(inGird.getGirdPointX(),inGird.getGirdPointY()));
						}
					}
				}
				return true;
			}
		};
		
		touchUpListener = new XXTouchListener() {
			
			@Override
			public boolean handle(XXTouchEvent event) {
				
				XXNode actor = event.getTarget();
				if(actor instanceof Chess){
					Chess chess = (Chess) actor;
					chess.unTouch() ;
					XX.director.addTween(XXTween.to(actor, XXNodeAccessor.POS_XY, 0.3f)
							.ease(Linear.INOUT).target(chess.getGirdPointX(),chess.getGirdPointY()));
					
					check();
				}
				return true;
			}
		};
		
		ChessColor.WRITE.textureRegion = new TextureRegion(new Texture("w.png"));
		ChessColor.BLACK.textureRegion = new TextureRegion(new Texture("b.png"));
		lable = XXLable.create("MARK:"+mark);
		timeLabel = XXLable.create("TIME:"+time);
		this.time = 60 ;
		this.setPosition(40, 40);
		chesses = new Chess[5][5] ;
		lable.setPosition(0,400);
		timeLabel.setPosition(0,360);
		randomFillChess();
		check() ;
		this.add(lable);
		this.add(timeLabel);
		
		XX.director.addSelector(new XXScheduleSelector() {
			
			@Override
			public void run() {
				time -- ;
				timeLabel.setText("TIME:"+time);
				List<XXParticle> tmp = new LinkedList<XXParticle>(particles);
				for(XXParticle particle : tmp){
					if(particle.isComplete()){
						particles.remove(particle);
						particle.dispose() ;
					}
				}
			}
		}, 1f) ;
	}

	protected void check() {
		HashSet<Chess> peterChess = new HashSet<Chess>();
		for(int x = 0 ; x < chesses.length ; x ++){
			for(int y = 0 ; y < chesses[x].length ; y ++){
				List<Chess> chesss = new LinkedList<ChessLayer.Chess>() ;
				Chess chess = chesses[x][y];
				chess.getColor().a = 1f ;
				findNext(chesss,chess,1,0);
				if(chesss.size() >= PETER_COUNT){
					peterChess.addAll(chesss);
				}
				chesss.clear() ;
				
				findNext(chesss,chess,1,1);
				if(chesss.size() >= PETER_COUNT){
					peterChess.addAll(chesss);
				}
				chesss.clear() ;
				
				findNext(chesss,chess,-1,1);
				if(chesss.size() >= PETER_COUNT){
					peterChess.addAll(chesss);
				}
				chesss.clear() ;
				
				findNext(chesss,chess,0,1);
				if(chesss.size() >= PETER_COUNT){
					peterChess.addAll(chesss);
				}
				chesss.clear() ;
				
				if(chesss.size() >= PETER_COUNT){
					peterChess.addAll(chesss);
				}
			}
		}
		this.mark += peterChess.size() ;
		this.lable.setText("MARK:"+this.mark);
		XXTween lastTween = null ;
		for(Chess chess : peterChess){
			XXParticle particle = XXParticle.create("a.p") ;
			particle.setPosition(chess.getX(), chess.getY());
			ChessLayer.this.add(particle);
			particles.add(particle);
			lastTween = XXTween.from(chess, XXNodeAccessor.OPACITY, 0.3f).ease(Linear.INOUT).target(0f).setCompleteCallBack(new XXTweenCallBack() {
				@Override
				public void doEvent(Object target, XXTween tween) {
					Chess chess = (Chess) target;
					chess.replaceChess(ChessColor.values()[RandomUtils.nextInt(2)]);
				}
			}).setUserData(chess);
			XX.director.addTween(lastTween);
		}
		if(lastTween != null){
			lastTween.setCompleteCallBack(new XXTweenCallBack() {
				
				@Override
				public void doEvent(Object target, XXTween tween) {
					final Chess chess = (Chess) target;
					XXParticle particle = XXParticle.create("a.p") ;
					particle.setPosition(chess.getX(), chess.getY());
					ChessLayer.this.add(particle);
					particles.add(particle);
					
					chess.replaceChess(ChessColor.values()[RandomUtils.nextInt(2)]);
					check() ;
				}

			});
		}
	}

	private void findNext(List<Chess> chesss,Chess chess, int x, int y) {
		chesss.add(chess);
		int nx = chess.girdPointX + x;
		int ny = chess.girdPointY + y;
		if(nx > 4 || ny > 4 || nx <0 || ny < 0){
			return ;
		}
		Chess nextChess = chesses[nx][ny]; 
		if(nextChess.chessColor == chess.chessColor && !chess.isTouch()){
			this.findNext(chesss, nextChess, x, y);
		}
	}

	protected void swapPosition(Chess chess, Chess toChess) {
		
		chesses[toChess.girdPointX][toChess.girdPointY] = chess ;
		chesses[chess.girdPointX][chess.girdPointY] = toChess ;
		
		int girdX = chess.girdPointX ;
		int girdY = chess.girdPointY ;
		chess.girdPointX = toChess.girdPointX;
		chess.girdPointY = toChess.girdPointY;
		
		toChess.girdPointX = girdX;
		toChess.girdPointY = girdY;
		
		this.mark -= 1 ;
		this.mark = Math.max(0, mark);
		this.lable.setText("MARK:"+this.mark);
	}

	private void randomFillChess() {
		for(int x = 0 ; x < chesses.length ; x ++){
			for(int y = 0 ; y < chesses[x].length ; y ++){
				chesses[x][y] = new Chess(x,y,ChessColor.values()[RandomUtils.nextInt(2)]) ;
				chesses[x][y].touchAble();
				chesses[x][y].setListener(XXEventType.TOUCHDRAGGED, dragedListener);
				chesses[x][y].setListener(XXEventType.CLICK_UP, touchUpListener);
				this.add(chesses[x][y]);
				XX.director.addTween(XXTween.from(chesses[x][y], XXNodeAccessor.POS_XY, 0.3f)
						.target(RandomUtils.nextFloat()*1800 - 900,RandomUtils.nextFloat()*1800 - 900));
			}
		}
	}
	
	public class Chess extends XXImage{

		ChessColor chessColor ;
		int girdPointX ;
		int girdPointY ;
		boolean touch ;
		
		public Chess(int x, int y, ChessColor chessColor) {
			this.setX( x * GIRD_WIDTH); 
			this.setY(y * GIRD_HEIGHT);
			this.girdPointX = x;
			this.girdPointY = y;
			this.chessColor = chessColor ;
			this.setTextureRegion(chessColor.getTextureRegion()) ;
		}
		
		public boolean isTouch(){
			return touch ;
		}
		
		public void touch(){
			touch = true ;
		}
		
		public void unTouch(){
			touch = false ;
		}
		
		public float getGirdPointX() {
			return this.girdPointX * GIRD_WIDTH;
		}

		public float getGirdPointY() {
			return this.girdPointY * GIRD_HEIGHT;
		}

		public void replaceChess(ChessColor chessColor){
			this.textureRegion = chessColor.getTextureRegion();
			this.chessColor = chessColor ;
		}
		
	}
	
	public enum ChessColor{
		
		WRITE("w.png"),
		BLACK("b.png"),
		;
		
		String imgPath ;
		TextureRegion textureRegion ;
		ChessColor(String imgPath){
			this.imgPath = imgPath ;
		}
		
		TextureRegion getTextureRegion(){
			return textureRegion ;
		}
	}
}
